// Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
#pragma once
#include "ILocationService.h"
#include <kdtree++/kdtree.hpp>
#include "TaskExceptionsExtensions.h"

namespace Weathr
{
    namespace Web
    {
        // Retrieves location information from a local text file on disk.
        class GeonamesLocationService : public ILocationService
        {
            // An entry in the k-d tree.
            struct Geoname
            {
                typedef float value_type;

                Geoname() = default;

                Geoname(const std::wstring& name, const std::wstring& adminDistrict, const std::wstring& countryRegion, float latitude, float longitude)
                    : Name(name), AdminDistrict(adminDistrict), CountryRegion(countryRegion), Latitude(latitude), Longitude(longitude)
                {
                }

                Geoname(Geoname&& other)
                {
                    Name = std::move(other.Name);
                    AdminDistrict = std::move(other.AdminDistrict);
                    CountryRegion = std::move(other.CountryRegion);
                    Latitude = other.Latitude;
                    Longitude = other.Longitude;
                }

                std::wstring Name;
                std::wstring AdminDistrict;
                std::wstring CountryRegion;
                float Latitude;
                float Longitude;

                value_type operator [](size_t n) const
                {
                    assert(n < 3);
                    return n == 0 ? Latitude : Longitude;
                }

                value_type distance(const Geoname& node)
                {
                    Weathr::LatLon a(Latitude, Longitude);
                    Weathr::LatLon b(node.Latitude, node.Longitude);

                    return static_cast<value_type>(DistanceInFeet(a, b));
                }
            };

        public:
            GeonamesLocationService(const std::wstring& namesFile, std::shared_ptr<ExceptionPolicy> exceptionPolicy);

            // Retrieves the location at the provided latitude and longitude coordinates.
            concurrency::task<std::shared_ptr<Location>> GetLocationAsync(float latitude, float longitude);

            // Retrieves all locations that match the provided string.
            concurrency::task<std::vector<std::shared_ptr<Location>>> GetLocationsAsync(const std::wstring& name);

            // Retrieves the name of the service.
            std::wstring GetServiceName() const;

        private:
            concurrency::task<void> ReadNamesFileAsync(std::wstring namesFile);

            std::shared_ptr<ExceptionPolicy> m_exceptionPolicy;
            concurrency::task<void> m_loadNamesFileTask;
            KDTree::KDTree<2, Geoname> m_locationTree;
        };
    }
}